import pandas as pd
import numpy as np
import plotly.graph_objects as go
# Para la realización de esta visualización se utilizará el set de datos EstadisticasAtaques2017_2020_Input_Visualization
# el cual tiene la distribución de ataques como variable categórica y no variable numérica.
url = 'https://raw.githubusercontent.com/iruiper/Cyberattacks-History/master/data/01_clean/EstadisticasAtaques2017_2020_Input_Visualization.csv'
# Columnas seleccionadas para realizar las visualizaciones
cols=['Continent', 'Author_processed', 'Code_attack_class', 'Desc_target_class']
df = pd.read_csv(url, sep=';', decimal=',', encoding='latin-1')
# Diccionario utilizado para ajustar las etiquetas en los gráficos
adjust_label = {
'Public administration and defence, compulsory social security': 'Public administration<br>and defence, compulsory<br>social security',
'Financial and insurance activities': 'Financial and<br>insurance activities',
'Information and communication': 'Information and<br>communication',
'Arts entertainment and recreation': 'Arts entertainment<br>and recreation',
'Human health and social work activities': 'Human health and<br>social work activities',
'Education': 'Education',
'Fintech': 'Fintech',
'Manufacturing': 'Manufacturing',
'Transportation and storage': 'Transportation and<br>storage',
'Professional scientific and technical activities': 'Professional scientific<br>and technical<br>activities',
'Other services activities': 'Other services<br>activities'
}
# Diccionario utilizado para modificar las etiquetas en los gráficos
attack_label = {
'H': 'Hactivism',
'CE': 'Cyber<br>Espionage',
'CC': 'Cyber<br>Crime',
'CW': 'Cyber<br>Warfare'
}
# Descartamos aquellos ataques internacionales y desconocidos, así como aquellos sectores detectados como outliers
data = df.loc[~(df.Continent.isin(['International', 'Desconocido'])) & ~(df.Code_target_class.isin(['X', 'Y', 'Z']))]
# Se asigna a las observaciones del sector público un color diferente para facilitar la detección de elementos en el gráfico.
data.loc[:, 'Color'] = data.Desc_target_class.map(lambda x: 'rgba(14,76,112,0.9)' if x == 'Public administration and defence, compulsory social security' else 'rgba(130,201,241,0.4)')
# Modificación de las descripciones de los sectores a traves del diccionario adjust_label
data.loc[:, 'Desc_target_class'] = data.Desc_target_class.where(data.Desc_target_class.map(adjust_label).isnull(),
data.Desc_target_class.map(adjust_label))
# Modificación de las tipologias de ataque
data.loc[:, 'Code_attack_class'] = data.Code_attack_class.map(attack_label)
def create_sankey(df, title):
"""
Función que permitirá crear un parallel set en función de los datos introducidos. Este parallel set contendrá
información de los 5 sectores más atacados en cada continente.
df: dataframe con los ataques filtrados por continente
title: título del gráfico.
"""
# Se agrupan los datos en función del sector atacado, contando el número de ataques recibidos en cada
# sector con el objetivo de obtener el top 5 sectores.
attack_df = df.groupby(['Desc_target_class'], as_index=False).count()
attack_df.sort_values('Mes', ascending=False, inplace=True)
# Filtramos el dataframe original quedándonos con aquellas observaciones que pertenezcan al top 5 de sectores
# atacados
data = df[df.Desc_target_class.isin(attack_df.head(5).Desc_target_class)]
# Creación de los distintos niveles del parallel set. El orden será Autor, Tipo de ataque y sector afetado
Author_dim = go.parcats.Dimension(values=data.Author_processed, label='Autor del Ataque')
Ataque_dim = go.parcats.Dimension(values=data.Code_attack_class, label='Tipo Ataque')
Target_dim = go.parcats.Dimension(values=data.Desc_target_class, label='Sector Afectado')
# Creación del gráfico
figg = go.Figure(data=[go.Parcats(dimensions=[Author_dim, Ataque_dim, Target_dim],
line={'color': data.Color})])
# Estética del gráfico.
figg.update_layout(
title={'text':title, 'x':0.5, 'xanchor':'center', 'yanchor': 'top'},
titlefont=dict(size=18),
height=500,
width=800,
showlegend=False
)
figg.show('notebook')